package com.basic.nio.groupchat;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;

/**
 * @Author: wisdom
 * @Date: 2024/4/1  8:11 PM
 * @Description:
 *
 * selector.keys 返回当前所有注册在selector中channel的selectionKey
 * selector.selectedKeys() 返回注册在selector中等待IO操作(及有事件发生)channel的selectionKey。
 *
 */
public class Server {

    public static void main(String[] args) throws IOException {
        //获取通道
        ServerSocketChannel server = ServerSocketChannel.open();
        //设置非阻塞
        server.configureBlocking(false);
        //绑定端口
        server.bind(new InetSocketAddress(9999));
        //获取选择器
        Selector selector = Selector.open();
        server.register(selector, SelectionKey.OP_ACCEPT);

        //遍历所有连接
        while (selector.select() > 0){
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
            while (iterator.hasNext()){
                SelectionKey sk = iterator.next();
                //客户端连接，注册到服务端
                if (sk.isAcceptable()) {
                    SocketChannel client = server.accept();
                    client.configureBlocking(false);
                    client.register(selector,SelectionKey.OP_READ);
                    System.out.println("客户端已连接！！！");
                } else if (sk.isReadable()) {
                    readMsg(sk,selector);
                }
                iterator.remove();
            }
        }
    }

    /**
     * 接受消息并发送给其它客户端
     * @param sk
     */
    private static void readMsg(SelectionKey sk,Selector selector) throws IOException {
        SocketChannel channel = null;
        try {
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            channel = (SocketChannel)sk.channel();
            int len = channel.read(buffer);
            if (len > 0){
                String msg = new String(buffer.array());
                System.out.println("收到客户端的消息："+msg.trim());

                //发送给其他客户端
                sendOther(selector,channel,msg);
            }
        }catch (Exception e){
            System.out.println("有人下线了");
            //取消注册
            sk.cancel();
            //关闭通道
            channel.close();
        }
    }

    /**
     * 发送给其他客户端
     * @param selector
     * @param channel
     * @param msg
     */
    private static void sendOther(Selector selector,SocketChannel channel, String msg) throws IOException {
        Set<SelectionKey> keys = selector.keys();
        for (SelectionKey key : keys) {
            if(key.channel() instanceof SocketChannel && !key.channel().equals(channel)){
                SocketChannel target = (SocketChannel) key.channel();
                //msg存到buffer
                ByteBuffer wrap = ByteBuffer.wrap(msg.getBytes());
                target.write(wrap);
                System.out.println("转发给其它客户端："+msg.trim());
            }
        }
    }
}
